/*****************************************************************************/ /*!
* file  : systask.c
* creat : apleilx
* note :  除初始化外，禁止该任务及其子程序使用含有阻塞的功能，包括数据存储，USB操作等等
* data  : 2019/07/02
*******************************************************************************/
#include "bsp_api.h"
#include "common.h"
#include "swap.h"
#include "fat_file_opt.h"
#include "simp_fat_update.h"

/*****************************************************************************
* @brief   const 
*****************************************************************************/
#define HASH_MD5_EN 0
#define HASH_SHA_EN 1

/*****************************************************************************
* @brief   function
*****************************************************************************/
int simp_fat_update_head_check(void);
int simp_fat_update_tab_check(void);
int simp_fat_update_main_check(void);

/*****************************************************************************
* @brief   extern var
*****************************************************************************/
extern const uint16_t ase_key_src[];
extern const uint8_t ase_key_ext[];

/*****************************************************************************
* @brief   simp_fat_update_check.
* @param   none
* @return  none
*****************************************************************************/
uint8_t simp_fat_update_check(char *fil_name)
{
	uint8_t aes_key[48];
	uu32 tick_start;

	dbg_puts("sd sfat verify start !\n\n");

	// status reset
	efat.md5_en = HASH_MD5_EN;
	efat.sha_en = HASH_SHA_EN;

	efat.hash_main_err = 0;
	efat.hash_tab_err = 0;

	efat.buff = malloc(2048 + 16);
	efat.hash_val = malloc(64 + 16);

	// hash init
	if (efat.md5_en)
	{
		efat.md5_obj = malloc(sizeof(mbedtls_md5_context));
	}

	if (efat.sha_en)
	{
		efat.sha_obj = malloc(sizeof(mbedtls_sha256_context));
	}

	// AES
	efat.aes_obj = malloc(sizeof(mbedtls_aes_context));
	mbedtls_aes_init(efat.aes_obj);

	// 192 BITS AES KEY => 24 BYTES
	copy_u8(ase_key_src, aes_key, 32);
	swap_bit_map_u16(aes_key, aes_key);
	map_add_u8(aes_key, (void *)ase_key_ext, aes_key, 32);
	mbedtls_aes_setkey_dec(efat.aes_obj, aes_key, 192);

	do
	{
		// 打开信息文件
		efat.fst = fat_fil_open(efat.fil, fil_name, FIL_OPEN_R);
		if (efat.fst != FIL_OPT_OK)
			break;

		// 文件头检测
		if (simp_fat_update_head_check())
		{
			break;
		}

		// 分配表检测
		simp_fat_update_tab_check();

		// 主文件数据检测
		simp_fat_update_main_check();
	} while (0);

	// 关闭文件
	efat.fst = fat_fil_close(efat.fil);

	// aes and hash free
	mbedtls_aes_free(efat.aes_obj);
	free(efat.aes_obj);

	if (efat.md5_en)
	{
		mbedtls_md5_free(efat.md5_obj);
		free(efat.md5_obj);
	}

	if (efat.sha_en)
	{
		mbedtls_sha256_free(efat.sha_obj);
		free(efat.sha_obj);
	}

	// verify info output
	if (efat.hash_main_err || efat.hash_tab_err)
	{
		dbg_puts("file verify fail !\n");
	}
	else
	{
		dbg_puts("file verify ok !\n");
	}

	free(efat.buff);
	free(efat.hash_val);

	return 0;
}

/*****************************************************************************
* @brief   simp_fat_update_head_check.
* @param   none
* @return  none
*****************************************************************************/
int simp_fat_update_head_check(void)
{
	uint32_t len_back;

	do
	{
		// 读取信息文件
		fat_fil_seek(efat.fil, 0);

		efat.fst = fat_fil_read(efat.fil, &efat.main_site, 18, &len_back);
		if (efat.fst != FIL_OPT_OK)
			break;

		// 信息验证
		if (efat.main_site < 0x80)
		{
			flash_dbg_puts("fil main site error !\n");
			break;
		}

		if (efat.info_site < efat.main_site + efat.main_len)
		{
			flash_dbg_puts("fil info site error !\n");
			break;
		}

		if (fat_fil_size(efat.fil) < efat.info_site + efat.info_len)
		{
			flash_dbg_puts("fil info size error !\n");
			break;
		}

		if (efat.main_aes_mode != 0x55 && efat.main_aes_mode != 0)
		{
			flash_dbg_puts("fil AES switch error !\n");
			break;
		}

		if (efat.info_aes_mode != 0x55 && efat.info_aes_mode != 0)
		{
			flash_dbg_puts("fil AES switch error !\n");
			break;
		}

		return 0;

	} while (0);

	return -1;
}

/*****************************************************************************
* @brief   simp_fat_update_tab_check.
* @param   none
* @return  none
*****************************************************************************/
int simp_fat_update_tab_check(void)
{
	uint32_t tick_start, len_back;

	// 读取文件分配表
	tick_start = app_tick_get();

	fat_fil_seek(efat.fil, efat.info_site);

	// hash
	if (efat.sha_en)
	{
		mbedtls_sha256_init(efat.sha_obj);
		mbedtls_sha256_starts(efat.sha_obj, 0);
	}

	if (efat.md5_en)
	{
		mbedtls_md5_init(efat.md5_obj);
		mbedtls_md5_starts(efat.md5_obj);
	}

	if (efat.info_aes_mode == 0x55)
	{
		uint8_t buff[32];
		int site, index, len;

		flash_dbg_puts("info is AES mode\n");

		for (site = 0; site < efat.info_len; site += 1024)
		{
			int rd_len;

			// 读取长度
			if (site + 1024 < efat.info_len)
				rd_len = 1024;
			else
				rd_len = efat.info_len - site;

			efat.fst = fat_fil_read(efat.fil, efat.buff, rd_len, &len_back);
			if (efat.fst != FIL_OPT_OK)
				break;

			for (index = 0; index < len_back; index += 16)
			{
				mbedtls_aes_crypt_ecb(efat.aes_obj, MBEDTLS_AES_DECRYPT, &efat.buff[index], buff);

				if (efat.sha_en)
				{
					mbedtls_sha256_update(efat.sha_obj, buff, 16);
				}

				if (efat.md5_en)
				{
					mbedtls_md5_update(efat.md5_obj, buff, 16);
				}
			}
		}
	}
	else
	{
		int site;

		flash_dbg_puts("info is NOR mode\n");

		for (site = 0; site < efat.info_len; site += 1024)
		{
			int rd_len;

			// 读取长度
			if (site + 1024 < efat.info_len)
				rd_len = 1024;
			else
				rd_len = efat.info_len - site;

			efat.fst = fat_fil_read(efat.fil, efat.buff, rd_len, &len_back);
			if (efat.fst != FIL_OPT_OK)
				break;

			if (efat.sha_en)
			{
				mbedtls_sha256_update(efat.sha_obj, efat.buff, len_back);
			}

			if (efat.md5_en)
			{
				mbedtls_md5_update(efat.md5_obj, efat.buff, len_back);
			}
		}
	}

	if (efat.sha_en)
	{
		mbedtls_sha256_finish(efat.sha_obj, efat.hash_val);
		dbg_u8_print("TAB   SHA: ", efat.hash_val, 32, 40);

		// 读取SHA值
		fat_fil_seek(efat.fil, 0x60);
		efat.fst = fat_fil_read(efat.fil, efat.buff, 32, &len_back);
		if (efat.fst != FIL_OPT_OK)
		{
			flash_dbg_puts("rad tab hash fail !\n");
		}

		if (0 == comp_u8(efat.buff, efat.hash_val, 32))
		{
			flash_dbg_puts("fat tab hash verify ok !\n");
		}
		else
		{
			flash_dbg_puts("fat tab hash verify fail !\n");
			efat.hash_tab_err++;
		}
	}

	if (efat.md5_en)
	{
		mbedtls_md5_finish(efat.md5_obj, efat.hash_val);
		dbg_u8_print("TAB   MD5: ", efat.hash_val, 16, 40);

		// 读取MD5值
		fat_fil_seek(efat.fil, 0x30);
		efat.fst = fat_fil_read(efat.fil, efat.buff, 16, &len_back);
		if (efat.fst != FIL_OPT_OK)
		{
			flash_dbg_puts("rad tab md5 fail !\n");
		}

		if (0 == comp_u8(efat.buff, efat.hash_val, 16))
		{
			flash_dbg_puts("fat tab md5 verify ok !\n");
		}
		else
		{
			flash_dbg_puts("fat tab md5 verify fail !\n");
			efat.hash_tab_err++;
		}
	}

	flash_dbg_print("time used : %d ms\n\n", app_tick_get() - tick_start);

	return efat.hash_tab_err;
}

/*****************************************************************************
* @brief   simp_fat_update_main_check.
* @param   none
* @return  none
*****************************************************************************/
int simp_fat_update_main_check(void)
{
	uint32_t tick_start, len_back;

	// 读取文件数据区
	tick_start = app_tick_get();

	fat_fil_seek(efat.fil, efat.main_site);

	// hash
	if (efat.sha_en)
	{
		mbedtls_sha256_init(efat.sha_obj);
		mbedtls_sha256_starts(efat.sha_obj, 0);
	}

	if (efat.md5_en)
	{
		mbedtls_md5_init(efat.md5_obj);
		mbedtls_md5_starts(efat.md5_obj);
	}

	if (efat.main_aes_mode == 0x55)
	{
		int site;

		flash_dbg_puts("file is AES mode\n");

		for (site = 0; site < efat.main_len; site += 1024)
		{
			int rd_len;
			int index;
			uint8_t buff[32];

			// 读取长度
			if (site + 1024 < efat.main_len)
				rd_len = 1024;
			else
				rd_len = efat.main_len - site;

			efat.fst = fat_fil_read(efat.fil, efat.buff, rd_len, &len_back);
			if (efat.fst != FIL_OPT_OK)
			{
				flash_dbg_puts("read file fail!\n");
				break;
			}

			for (index = 0; index < rd_len; index += 16)
			{
				// AES 解密
				mbedtls_aes_crypt_ecb(efat.aes_obj, MBEDTLS_AES_DECRYPT, &efat.buff[index], buff);

				// HASH 校验
				if (efat.sha_en)
				{
					mbedtls_sha256_update(efat.sha_obj, buff, 16);
				}

				if (efat.md5_en)
				{
					mbedtls_md5_update(efat.md5_obj, buff, 16);
				}
			}
		}
	}
	else
	{
		int site;

		flash_dbg_puts("file is NOR mode\n");

		for (site = 0; site < efat.main_len; site += 1024)
		{
			int rd_len;

			// 读取长度
			if (site + 1024 < efat.main_len)
				rd_len = 1024;
			else
				rd_len = efat.main_len - site;

			efat.fst = fat_fil_read(efat.fil, efat.buff, rd_len, &len_back);
			if (efat.fst != FIL_OPT_OK)
				break;

			// HASH calculate
			if (efat.sha_en)
			{
				mbedtls_sha256_update(efat.sha_obj, efat.buff, len_back);
			}

			if (efat.md5_en)
			{
				mbedtls_md5_update(efat.md5_obj, efat.buff, len_back);
			}
		}
	}

	if (efat.sha_en)
	{
		mbedtls_sha256_finish(efat.sha_obj, efat.hash_val);
		dbg_u8_print("MAIN  SHA: ", efat.hash_val, 32, 40);

		// 读取SHA值
		fat_fil_seek(efat.fil, 0x40);
		efat.fst = fat_fil_read(efat.fil, efat.buff, 32, &len_back);
		if (efat.fst != FIL_OPT_OK)
		{
			flash_dbg_puts("SHA: read main SHA fail !\n");
		}

		if (0 == comp_u8(efat.buff, efat.hash_val, 32))
		{
			flash_dbg_puts("SHA: fat main SHA verify ok !\n");
		}
		else
		{
			flash_dbg_puts("SHA: fat main SHA verify fail !\n");
			efat.hash_main_err++;
		}
	}

	if (efat.md5_en)
	{
		mbedtls_md5_finish(efat.md5_obj, efat.hash_val);
		dbg_u8_print("TAB   MD5: ", efat.hash_val, 16, 40);

		// 读取MD5值
		fat_fil_seek(efat.fil, 0x20);
		efat.fst = fat_fil_read(efat.fil, efat.buff, 16, &len_back);
		if (efat.fst != FIL_OPT_OK)
		{
			flash_dbg_puts("MD5: read tab MD5 fail !\n");
		}

		if (0 == comp_u8(efat.buff, efat.hash_val, 16))
		{
			flash_dbg_puts("MD5: fat tab MD5 verify ok !\n");
		}
		else
		{
			flash_dbg_puts("MD5: fat tab MD5 verify fail !\n");
			efat.hash_main_err++;
		}
	}

	flash_dbg_print("file size : %d KB\n", efat.main_len);
	flash_dbg_print("time used : %d ms\n\n", app_tick_get() - tick_start);

	return efat.hash_main_err;
}
